﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using ImageConverter.Configuration;
using ImageConverter.Pooling;
namespace ImageConverter.Utils.Bitmap
{
    public class AspectsTable : IAspectsTable
    {
        public AspectsTable()
        {
            table = new Dictionary<double?, Dimensions>();

            VerticalAspectBoundary = new SizeBoundary(1, 1);
            HorizontalAspectBoundary = new SizeBoundary(1, 1);
        }

        public string ToXml()
        {
            XDocument doc = new XDocument();
            XElement root = new XElement("aspects");

            foreach (var kvp in table)
            {
                XElement aspectNode = new XElement("aspect",
                    new XAttribute("key", String.Format("{0:0.000}", (double)kvp.Key)),
                    new XAttribute("width", kvp.Value.Width),
                    new XAttribute("height", kvp.Value.Height)
                    );

                root.Add(aspectNode);
            }

            doc.Add(root);

            return doc.ToString();
        }

        #region IAspectsTable Members

        public SizeBoundary VerticalAspectBoundary { get; private set; }

        public SizeBoundary HorizontalAspectBoundary { get; private set; }

        public Dimensions GetRecodeDimensions(int width, int height)
        {
            if (width <= 0 || height <= 0)
                return Dimensions.Empty;

            double aspect = (double)width / (double)height;

            Dimensions recodeDim = Dimensions.Empty;

            var key = table.Keys.Where(k => Math.Abs((double)k - aspect) < 0.01).FirstOrDefault();

            if (key != null)
            {
                return table[key];
            }

            return Dimensions.Empty;
        }

        public bool IsSmallImage(int width, int height)
        {
            bool result = false;

            bool isVertical = ((double)width / (double)height) < 1;

            if (isVertical)
                result = width < VerticalAspectBoundary.MinWidth && height < VerticalAspectBoundary.MinHeight;
            else
                result = width < HorizontalAspectBoundary.MinWidth && height < HorizontalAspectBoundary.MinHeight;

            return result;
        }

        public void AddAspect(double aspect, int width, int height)
        {

            double calculatedAspect = (double)width / (double)height;
            if (Math.Abs(aspect - calculatedAspect) < 0.001)
            {
                table[aspect] = DimensionsPool.Create(width, height);
            }

            SetupBoundaries();
        }

        #endregion

        #region Private methods

        private void SetupBoundaries()
        {
            var verticalAligned = table.Where(k => k.Value.CalculateAspect() < 1).
                Select(k => k.Value);
            var horizontalAligned = table.Where(k => k.Value.CalculateAspect() >= 1).
                Select(k => k.Value);

            if (verticalAligned.Count() > 0 && horizontalAligned.Count() > 0)
            {
                VerticalAspectBoundary = new SizeBoundary(verticalAligned.Min(d => d.Width), verticalAligned.Min(d => d.Height));
                HorizontalAspectBoundary = new SizeBoundary(horizontalAligned.Min(d => d.Width), horizontalAligned.Min(d => d.Height));
            }
        }

        #endregion

        #region Private fields

        private Dictionary<double?, Dimensions> table;

        #endregion
    }
}
